a tool for shared writing and social publishing
1import { z } from "zod";
2import { makeRoute } from "../lib";
3import type { Env } from "./route";
4import { idResolver } from "app/(home-pages)/reader/idResolver";
5import { supabaseServerClient } from "supabase/serverClient";
6import { Agent } from "@atproto/api";
7import { getIdentityData } from "actions/getIdentityData";
8import { createOauthClient } from "src/atproto-oauth";
9import {
10 normalizePublicationRow,
11 hasValidPublication,
12} from "src/utils/normalizeRecords";
13
14export type GetProfileDataReturnType = Awaited<
15 ReturnType<(typeof get_profile_data)["handler"]>
16>;
17
18export const get_profile_data = makeRoute({
19 route: "get_profile_data",
20 input: z.object({
21 didOrHandle: z.string(),
22 }),
23 handler: async ({ didOrHandle }, { supabase }: Pick<Env, "supabase">) => {
24 // Resolve handle to DID if necessary
25 let did = didOrHandle;
26
27 if (!didOrHandle.startsWith("did:")) {
28 const resolved = await idResolver.handle.resolve(didOrHandle);
29 if (!resolved) {
30 throw new Error("Could not resolve handle to DID");
31 }
32 did = resolved;
33 }
34 let agent;
35 let authed_identity = await getIdentityData();
36 if (authed_identity?.atp_did) {
37 try {
38 const oauthClient = await createOauthClient();
39 let credentialSession = await oauthClient.restore(
40 authed_identity.atp_did,
41 );
42 agent = new Agent(credentialSession);
43 } catch (e) {
44 agent = new Agent({
45 service: "https://public.api.bsky.app",
46 });
47 }
48 } else {
49 agent = new Agent({
50 service: "https://public.api.bsky.app",
51 });
52 }
53
54 let profileReq = agent.app.bsky.actor.getProfile({ actor: did });
55
56 let publicationsReq = supabase
57 .from("publications")
58 .select("*")
59 .eq("identity_did", did);
60
61 let [{ data: profile }, { data: publications }] = await Promise.all([
62 profileReq,
63 publicationsReq,
64 ]);
65
66 // Normalize publication records before returning
67 const normalizedPublications = (publications || [])
68 .map(normalizePublicationRow)
69 .filter(hasValidPublication);
70
71 return {
72 result: {
73 profile,
74 publications: normalizedPublications,
75 },
76 };
77 },
78});